<template>
    <el-upload v-model:file-list="fileList" action="#" multiple :limit="limit" :http-request="handleXhr"
        :before-upload="handleBeforeUpload" :on-preview="handlePreview" :on-remove="handleRemove"
        :on-exceed="handleExceed">
        <el-button type="primary">浏览文件</el-button>
        <template #tip>
            <div class="el-upload__tip">
                文件大小不超过 {{maxSizeText}}.
            </div>
        </template>
    </el-upload>
</template>

<script setup>
/**
 * 图片上传组件
 */
import { ref, watch } from 'vue'
import { ElMessage } from 'element-plus'
import EsAjax from '@/utils/EsAjax';
import ApiUrls from '@/apis/index';

// ======================================================
//                      功能函数
// ======================================================

/**
 * 字节单位转换
 */
 const bytesToSize = (bytes) => {
    if (bytes === 0) {
        return '0 B';
    }
    var k = 1024, // or 1024
        sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
        i = Math.floor(Math.log(bytes) / Math.log(k));

    return (bytes / Math.pow(k, i)).toPrecision(3) + ' ' + sizes[i];
}

// ======================================================
//                      变量声明
// ======================================================

// props
const props = defineProps({
    modelValue: Array,
    limit: {
        type: Number,
        default: 5
    },
    maxSize: {
        type: Number,
        default: 500 * 1024,
    }
})
// emit（v-model 使用在原生控件为: value @input，使用在组件为: modelValue @update:modelValue）
const emit = defineEmits(['update:modelValue']);
// 文件路径 [{name,url}]
const fileList = ref(props.modelValue);
const files = ref(props.modelValue);
// watch
watch(() => props.modelValue, (newVal) => {
    fileList.value = newVal;
    files.value = newVal;
})
// 文件类型
const exts = ['xls', 'xlsx', 'doc', 'docx', 'ppt', 'pptx', 'wps', 'et', 'dps', 'csv', 'txt', 'rtf', 'xml', 'json', 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'webp', 'mp3', 'mp4'];
// 文件大小提示
const maxSizeText = bytesToSize(props.maxSize);

// ======================================================
//                      处理事件
// ======================================================

// 处理上传文件之前的钩子
const handleBeforeUpload = (rawFile) => {
    let pos = rawFile.name.lastIndexOf('.');
    if (pos == -1) {
        ElMessage.error('文件后缀名无效！')
        return false;
    }
    if (!exts.includes(rawFile.name.substring(pos + 1).toLowerCase())) {
        ElMessage.error('该文件类型禁止上传！' + rawFile.name)
        return false;
    }
    if (rawFile.size > props.maxSize) {
        ElMessage.error('单个文件不能超过 ' + maxSizeText + '!')
        return false;
    }
    return true
}

// 处理上传文件的请求
const handleXhr = (xhr) => {
    let formData = new FormData();
    formData.set('file', xhr.file);
    EsAjax.post(ApiUrls.upload, formData).then(res => {
        if (res.data.errcode) {
            ElMessage.warning(res.data.data+res.data.msg);
            return;
        }
        files.value = files.value.concat(res.data.data);
        emit('update:modelValue', files.value.map(item => { return { name: item.name, url: item.url } }));
    }).catch(err => { ElMessage.error('网络错误：' + err.message) })
}

// 处理文件列表移除文件时的钩子
const handleRemove = (uploadFile, uploadFiles) => {
    files.value = [];
    uploadFiles.forEach(item => {
        files.value.push({ name: item.name, url: item.url });
    })
}

// 处理点击文件列表中已上传的文件时的钩子
const handlePreview = (uploadFile) => {
    window.open(uploadFile.url, "_blank");
}

// 处理超出限制时的钩子
const handleExceed = (files, uploadFiles) => {
    ElMessage.warning(
        `最多上传  ${props.limit} 个文件，您刚选择 ${files.length} 个文件，累计 ${files.length + uploadFiles.length} 个文件。`
    )
}

</script>
  